#ifndef __TRAITS_H_
#define __TRAITS_H_

namespace stl
{

// helper typename:
template <typename T, T v> struct integral_constant
{
    const static T value = v;
};

typedef integral_constant<bool, true>  true_type;
typedef integral_constant<bool, false> false_type;

// helper traits
template <bool, typename T = void> struct enable_if
{
};

template <typename T>
struct enable_if <true, T>
{
    typedef T type;
};

template <bool, typename T, typename F> struct conditional
{
    typedef T type;
};

template <typename T, typename F> 
struct conditional <false, T, F>
{
    typedef F type;
};

// Primary typenameification traits:
template <typename T> struct is_void : public false_type {};
template <> struct is_void <void> : public true_type {};

template <typename T> struct is_integral : public false_type {};
template <> struct is_integral <bool> : public true_type {};
template <> struct is_integral <char> : public true_type {};
template <> struct is_integral <signed char> : public true_type {};
template <> struct is_integral <unsigned char> : public true_type {};
template <> struct is_integral <wchar_t> : public true_type {};

template <> struct is_integral <short> : public true_type {};
template <> struct is_integral <unsigned short> : public true_type {};
template <> struct is_integral <int> : public true_type {};
template <> struct is_integral <unsigned int> : public true_type {};
template <> struct is_integral <long> : public true_type {};
template <> struct is_integral <unsigned long> : public true_type {};
template <> struct is_integral <long long> : public true_type {};
template <> struct is_integral <unsigned long long> : public true_type {};

template <typename T> struct is_floating_point : public false_type {};
template <> struct is_floating_point <float> : public true_type {};
template <> struct is_floating_point <double> : public true_type {};
template <> struct is_floating_point <long double> : public true_type {};

template <typename T> struct is_array : public false_type {};
template <typename T> struct is_array <T[]> : public true_type {};
template <typename T, size_t size> struct is_array <T[size]> : public true_type {};

template <typename T> struct is_pointer : public false_type {};
template <typename T> struct is_pointer <T*> : public true_type {};
template <typename T> struct is_pointer <const T*> : public true_type {};

template <typename T> struct is_lvalue_reference : public false_type {};
template <typename T> struct is_lvalue_reference <T&> : public true_type {};
template <typename T> struct is_lvalue_reference <const T&> : public true_type {};

template <typename T> struct is_rvalue_reference : public false_type {};
template <typename T> struct is_rvalue_reference <T&&> : public true_type {};
template <typename T> struct is_rvalue_reference <const T&&> : public true_type {};

template <typename T> struct is_member_object_pointer;

template <typename T> struct is_member_function_pointer : public false_type {};
template <typename T> struct is_member_function_pointer : public false_type {};

template <typename T> struct is_enum;
template <typename T> struct is_union;
template <typename T> struct is_typename;
template <typename T> struct is_function;

// Secondary typename identification traits:
template <typename T> struct is_reference : public false_type {};
template <typename T> struct is_reference <T&> : public true_type {};
template <typename T> struct is_reference <T&&>: public true_type {};

template <typename T> struct is_arithmetic : public integral_constant
    <bool, is_integral<T>::value || is_floating_point<T>::value> {};

template <typename T> struct is_fundamental;
template <typename T> struct is_member_pointer;
template <typename T> struct is_scalar;
template <typename T> struct is_object;
template <typename T> struct is_compound;

// Const-volatile properties and transformations:
template <typename T> struct is_const;
template <typename T> struct is_volatile;
template <typename T> struct remove_const;
template <typename T> struct remove_volatile;
template <typename T> struct remove_cv;
template <typename T> struct add_const;
template <typename T> struct add_volatile;
template <typename T> struct add_cv;

// Reference transformations:
template <typename T> struct remove_reference;
template <typename T> struct add_lvalue_reference;
template <typename T> struct add_rvalue_reference;

// Pointer transformations:
template <typename T> struct remove_pointer;
template <typename T> struct add_pointer;

// Integral properties:
template <typename T> struct is_signed;
template <typename T> struct is_unsigned;
template <typename T> struct make_signed;
template <typename T> struct make_unsigned;

// Array properties and transformations:
template <typename T> struct rank;
template <typename T, unsigned I = 0> struct extent;
template <typename T> struct remove_extent;
template <typename T> struct remove_all_extents;

// Member introspection:
template <typename T> struct is_pod;
template <typename T> struct is_trivial;

/*A trivially copyable class is a class that:
1. Has no non-trivial copy constructors (this also requires no virtual functions or virtual bases)
2. Has no non-trivial move constructors
3. Has no non-trivial copy assignment operators
4. Has no non-trivial move assignment operators
5. Has a trivial destructor*/
template <typename T> struct is_trivially_copyable;

template <typename T> struct is_standard_layout;
template <typename T> struct is_literal_type;
template <typename T> struct is_empty;
template <typename T> struct is_polymorphic;
template <typename T> struct is_abstract;

//template <typename T, typename... Args> struct is_constructible;
template <typename T> struct is_default_constructible;
template <typename T> struct is_copy_constructible;
template <typename T> struct is_move_constructible;
template <typename T, typename U> struct is_assignable;
template <typename T> struct is_copy_assignable;
template <typename T> struct is_move_assignable;
template <typename T> struct is_destructible;

//template <typename T, typename... Args> struct is_trivially_constructible;
template <typename T> struct is_trivially_default_constructible;
template <typename T> struct is_trivially_copy_constructible;
template <typename T> struct is_trivially_move_constructible;
template <typename T, typename U> struct is_trivially_assignable;
template <typename T> struct is_trivially_copy_assignable;
template <typename T> struct is_trivially_move_assignable;
template <typename T> struct is_trivially_destructible;

//template <typename T, typename... Args> struct is_nothrow_constructible;
template <typename T> struct is_nothrow_default_constructible;
template <typename T> struct is_nothrow_copy_constructible;
template <typename T> struct is_nothrow_move_constructible;
template <typename T, typename U> struct is_nothrow_assignable;
template <typename T> struct is_nothrow_copy_assignable;
template <typename T> struct is_nothrow_move_assignable;
template <typename T> struct is_nothrow_destructible;

template <typename T> struct has_virtual_destructor;

// Relationships between types:
template <typename T, typename U> struct is_same;
template <typename Base, typename Derived> struct is_base_of;
template <typename From, typename To> struct is_convertible;

// Alignment properties and transformations:
template <typename T> struct alignment_of;
template <size_t Len, size_t Align = most_stringent_alignment_requirement>
struct aligned_storage;
//template <std::size_t Len, typename... Types> struct aligned_union;

template <typename T> struct decay;
//template <typename... T> struct common_type;
template <typename T> struct underlying_type;
//template <typename> typename result_of; // undefined
//template <typename Fn, typename... ArgTypes> typename result_of<Fn(ArgTypes...)>;

}//namespace stl

#endif